package jalgebrava.group.groups;

import jalgebrava.group.Group;
import jalgebrava.group.permutation.Permutation;
import jalgebrava.util.F;
import jalgebrava.util.collections.ImmutableIterable;

final class SymmetricGroupFactory {
	@SuppressWarnings("unused") // just there to keep EMMA happy
	private final static SymmetricGroupFactory instance = new SymmetricGroupFactory();
	private SymmetricGroupFactory() {
		// empty
	}
	
	private final static F<Integer, Group<Permutation>> makeFunction 
		= F.cached(new F<Integer, Group<Permutation>>(){

			@Override
			public Group<Permutation> apply(Integer a) {
				return SymmetricGroupFactory.mkWorker(a);
			}
			
		}); 
	
	final static Group<Permutation> mk(int n) {
		return makeFunction.apply(n);
	}
	private final static Group<Permutation> mkWorker(final int n) {
		ImmutableIterable<Permutation> it = Permutation.allPermutationsOfSize(n);
		if (n > 12) {
			throw new RuntimeException("Sym(" + n + ") would exceed size of int");
		}
		return new AbstractGroup<Permutation>("S("+n+")", it, factorial(n)) {

			@Override
			public Permutation unit() {
				return Permutation.identityPermutation(n);
			}

			@Override
			public Permutation inv(Permutation x) {
				return x.inversePermutation();
			}

			@Override
			public Permutation mul(Permutation x, Permutation y) {
				return x.multiplyPermutation(y);
			}

			@Override
			public boolean contains(Permutation x) {
				return x.getSizeOfSetActedUpon() == n;
			}
			
		};
	}
	private final static int factorial(int n) {
		
		int result = 1;
		for (int i=2;i<=n;i++) {
		
			result *= i;
		}
		
		return result;
	}
}
